package my;

import javax.xml.namespace.QName;
import javax.xml.soap.*;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import javax.xml.ws.Service;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPBinding;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Client {
    private static final String ENDPOINT_URL = "http://localhost:8080/student";

    public static void main(String[] args) throws Exception {
        System.out.println("=== 开始测试 ===");

        // 1. 先测试手动SOAP消息调用
        System.out.println("\n1. 测试手动SOAP消息调用:");
        sendCustomSoapMessage();

        // 等待一段时间确保服务端处理完成
        Thread.sleep(1000);

        // 2. 再测试标准JAX-WS调用（带Header）
        System.out.println("\n2. 测试标准JAX-WS调用（带Header）:");
        try {
            URL wsdlUrl = new URL(ENDPOINT_URL + "?wsdl");
            QName serviceName = new QName("http://my/", "StudentService");
            Service service = Service.create(wsdlUrl, serviceName);
            IService port = service.getPort(IService.class);

            // 为客户端添加Handler来添加Header
            BindingProvider bp = (BindingProvider) port;
            List<Handler> handlerChain = new ArrayList<>();
            handlerChain.add(new ClientSOAPHandler()); // 使用专门的客户端Handler
            bp.getBinding().setHandlerChain(handlerChain);

            System.out.println("标准调用响应: " + port.hello("JAXWS-Test"));
        } catch (Exception e) {
            System.err.println("标准调用失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void sendCustomSoapMessage() {
        try {
            // 使用SOAP 1.1协议
            MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
            SOAPMessage message = mf.createMessage();

            // 设置正确的Content-Type
            MimeHeaders headers = message.getMimeHeaders();
            headers.setHeader("Content-Type", "text/xml; charset=utf-8");
            headers.setHeader("SOAPAction", "\"\""); // 添加SOAPAction头

            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();

            // 确保正确的命名空间声明
            envelope.addNamespaceDeclaration("ns", "http://my/");

            // 添加自定义 Header
            SOAPHeader header = envelope.getHeader();
            if (header == null) {
                header = envelope.addHeader();
            }

            // 创建student元素，明确指定命名空间
            SOAPElement student = header.addChildElement("student", "ns", "http://my/");
            student.addChildElement("sno", "ns", "http://my/").addTextNode("3221003139");
            student.addChildElement("sname", "ns", "http://my/").addTextNode("邓金玲");

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
            String currentTime = LocalDate.now().format(formatter);
            student.addChildElement("time", "ns", "http://my/").addTextNode(currentTime);

            // 构造 Body
            SOAPBody body = envelope.getBody();
            SOAPElement hello = body.addChildElement("hello", "ns", "http://my/");
            SOAPElement username = hello.addChildElement("username", "ns", "http://my/");
            username.addTextNode("3221003139");

            // 打印请求消息以便调试
            System.out.println("发送的SOAP消息:");
            message.writeTo(System.out);
            System.out.println("\n");

            // 发送请求
            SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
            System.out.println("发送SOAP 1.1消息到: " + ENDPOINT_URL);

            SOAPMessage response = connection.call(message, ENDPOINT_URL);

            if (response != null) {
                System.out.println("响应状态: 成功");
                System.out.println("响应内容:");
                response.writeTo(System.out);
                System.out.println("\n");
            } else {
                System.out.println("未收到响应");
            }
            connection.close();

        } catch (Exception e) {
            System.err.println("SOAP调用失败: " + e.getClass().getSimpleName() + ": " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 客户端专用的SOAP Handler，用于添加Header
    static class ClientSOAPHandler implements SOAPHandler<SOAPMessageContext> {

        @Override
        public boolean handleMessage(SOAPMessageContext context) {
            Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

            try {
                SOAPMessage message = context.getMessage();

                if (isOutbound) {
                    // 出站消息：客户端发送请求时添加Header
                    System.out.println("客户端Handler: 添加Header到出站消息");
                    addStudentHeader(message);
                } else {
                    // 入站消息：客户端接收响应时读取Header
                    System.out.println("客户端Handler: 处理入站响应消息");
                }

                // 打印消息内容用于调试
                System.out.println("=== 客户端SOAP消息内容 ===");
                message.writeTo(System.out);
                System.out.println("\n========================");

            } catch (Exception e) {
                System.err.println("客户端Handler处理异常: " + e.getMessage());
                e.printStackTrace();
                return false;
            }

            return true;
        }

        private void addStudentHeader(SOAPMessage message) throws SOAPException {
            SOAPHeader header = message.getSOAPHeader();
            if (header == null) {
                header = message.getSOAPPart().getEnvelope().addHeader();
            }

            // 添加命名空间声明
            String namespace = "http://my/";
            String prefix = "ns";

            // 创建student元素
            SOAPElement student = header.addChildElement("student", prefix, namespace);
            student.addChildElement("sno", prefix, namespace).addTextNode("3221003139");
            student.addChildElement("sname", prefix, namespace).addTextNode("邓金玲");

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
            String currentTime = LocalDate.now().format(formatter);
            student.addChildElement("time", prefix, namespace).addTextNode(currentTime);

            System.out.println("客户端Handler: 已添加student header");
        }

        @Override
        public boolean handleFault(SOAPMessageContext context) {
            System.out.println("客户端Handler: 处理Fault");
            return false;
        }

        @Override
        public void close(MessageContext context) {
            System.out.println("客户端Handler: 关闭");
        }

        @Override
        public Set<QName> getHeaders() {
            return Collections.singleton(new QName("http://my/", "student"));
        }
    }
}